• Зачем визуализировать данные
    • Квартет Энскомба
    • Datasaurus
  • Загрузка датасета
  • Базовые функции визуализации
  • Библиотека ggplot2
  • corrplot
  • Интерактивные визуализации
  • PS

Установка и подключение необходимых библиотек

#install.packages('gsheet', dep = T)
#install.packages('tidyverse', dep = T)

library(gsheet)
library(tidyverse)
library(lubridate)

Зачем визуализировать данные

Квартет Энскомба

Квартет Энскомба — четыре набора числовых данных, у которых простые статистические свойства идентичны, но их графики существенно отличаются. Каждый набор состоит из 11 пар чисел. Квартет был составлен в 1973 году английским математиком Ф. Дж. Энскомбом для иллюстрации важности применения графиков для статистического анализа, и влияния выбросов значений на свойства всего набора данных.

Эти данные состоят из четырёх пар x и y с практически равным средним значением (M[xi]=9, M[yi]=7.5) и дисперсией между соответствующими элементами пар (D[xi]=11, D[yi]≈4.13) , а также равным коэффициентом корреляции (cor(xi,yi)=0.816). Модель линейной регрессии, построенная методом МНК для всех вариантов описывается уравнением y=3.00+0.500x [2].

Графики представлены на рисунке ниже , из которого видно, насколько могут различаться данные, описываемые внешне статистически одинаково.

require(stats); require(graphics)
asc <- anscombe
asc
ABCDEFGHIJ0123456789
x1
<dbl>
x2
<dbl>
x3
<dbl>
x4
<dbl>
y1
<dbl>
y2
<dbl>
y3
<dbl>
y4
<dbl>
10101088.049.147.466.58
88886.958.146.775.76
13131387.588.7412.747.71
99988.818.777.118.84
11111188.339.267.818.47
14141489.968.108.847.04
66687.246.136.085.25
444194.263.105.3912.50
121212810.849.138.155.56
77784.827.266.427.91
##-- now some "magic" to do the 4 regressions in a loop:
ff <- y ~ x
mods <- setNames(as.list(1:4), paste0("lm", 1:4))
for(i in 1:4) {
  ff[2:3] <- lapply(paste0(c("y","x"), i), as.name)
  ## or   ff[[2]] <- as.name(paste0("y", i))
  ##      ff[[3]] <- as.name(paste0("x", i))
  mods[[i]] <- lmi <- lm(ff, data = anscombe)
  print(anova(lmi))
}
## Analysis of Variance Table
## 
## Response: y1
##           Df Sum Sq Mean Sq F value  Pr(>F)   
## x1         1 27.510 27.5100   17.99 0.00217 **
## Residuals  9 13.763  1.5292                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Analysis of Variance Table
## 
## Response: y2
##           Df Sum Sq Mean Sq F value   Pr(>F)   
## x2         1 27.500 27.5000  17.966 0.002179 **
## Residuals  9 13.776  1.5307                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Analysis of Variance Table
## 
## Response: y3
##           Df Sum Sq Mean Sq F value   Pr(>F)   
## x3         1 27.470 27.4700  17.972 0.002176 **
## Residuals  9 13.756  1.5285                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Analysis of Variance Table
## 
## Response: y4
##           Df Sum Sq Mean Sq F value   Pr(>F)   
## x4         1 27.490 27.4900  18.003 0.002165 **
## Residuals  9 13.742  1.5269                    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## See how close they are (numerically!)
sapply(mods, coef)
##                   lm1      lm2       lm3       lm4
## (Intercept) 3.0000909 3.000909 3.0024545 3.0017273
## x1          0.5000909 0.500000 0.4997273 0.4999091
lapply(mods, function(fm) coef(summary(fm)))
## $lm1
##              Estimate Std. Error  t value    Pr(>|t|)
## (Intercept) 3.0000909  1.1247468 2.667348 0.025734051
## x1          0.5000909  0.1179055 4.241455 0.002169629
## 
## $lm2
##             Estimate Std. Error  t value    Pr(>|t|)
## (Intercept) 3.000909  1.1253024 2.666758 0.025758941
## x2          0.500000  0.1179637 4.238590 0.002178816
## 
## $lm3
##              Estimate Std. Error  t value    Pr(>|t|)
## (Intercept) 3.0024545  1.1244812 2.670080 0.025619109
## x3          0.4997273  0.1178777 4.239372 0.002176305
## 
## $lm4
##              Estimate Std. Error  t value    Pr(>|t|)
## (Intercept) 3.0017273  1.1239211 2.670763 0.025590425
## x4          0.4999091  0.1178189 4.243028 0.002164602
## Now, do what you should have done in the first place: PLOTS
op <- par(mfrow = c(2, 2), mar = 0.1+c(4,4,1,1), oma =  c(0, 0, 2, 0))
for(i in 1:4) {
  ff[2:3] <- lapply(paste0(c("y","x"), i), as.name)
  plot(ff, data = anscombe, col = "red", pch = 21, bg = "orange", cex = 1.2,
       xlim = c(3, 19), ylim = c(3, 13))
  abline(mods[[i]], col = "blue")
}
mtext("Anscombe's 4 Regression data sets", outer = TRUE, cex = 1.5)

Datasaurus

Еще один интересный датасет на эту тему. И опять таки - все статистики очень близки. Но если их визуализировать…

library(datasauRus)
datasaurus_dozen
ABCDEFGHIJ0123456789
dataset
<chr>
x
<dbl>
y
<dbl>
dino55.3846097.17950000
dino51.5385096.02560000
dino46.1538094.48720000
dino42.8205091.41030000
dino40.7692088.33330000
dino38.7179084.87180000
dino35.6410079.87180000
dino33.0769077.56410000
dino28.9744074.48720000
dino26.1538071.41030000
if(requireNamespace("dplyr")){
  suppressPackageStartupMessages(library(dplyr))
  datasaurus_dozen %>% 
    group_by(dataset) %>% 
    summarize(
      mean_x    = mean(x),
      mean_y    = mean(y),
      std_dev_x = sd(x),
      std_dev_y = sd(y),
      corr_x_y  = cor(x, y)
    )
}
ABCDEFGHIJ0123456789
dataset
<chr>
mean_x
<dbl>
mean_y
<dbl>
std_dev_x
<dbl>
std_dev_y
<dbl>
corr_x_y
<dbl>
away54.2661047.8347216.7698226.93974-0.06412835
bullseye54.2687347.8308216.7692426.93573-0.06858639
circle54.2673247.8377216.7600126.93004-0.06834336
dino54.2632747.8322516.7651426.93540-0.06447185
dots54.2603047.8398316.7677426.93019-0.06034144
h_lines54.2614447.8302516.7659026.93988-0.06171484
high_lines54.2688147.8354516.7667026.94000-0.06850422
slant_down54.2678547.8359016.7667626.93610-0.06897974
slant_up54.2658847.8315016.7688526.93861-0.06860921
star54.2673447.8395516.7689626.93027-0.06296110
if(requireNamespace("ggplot2")){
  library(ggplot2)
  ggplot(datasaurus_dozen, aes(x=x, y=y, colour=dataset))+
    geom_point()+
    theme_void()+
    theme(legend.position = "none")+
    facet_wrap(~dataset, ncol=3)
}

Загрузка датасета

Загрузим данные по погоде: Киев, Харьков, Львов, Одесса за период: 01.10.2012 - 27.10.2018

Для тех у кого мало памяти и слабые ноутбуки -

url <- ‘docs.google.com/spreadsheets/d/1rJCuU5NLj7_Z45Hs6vxpjJHvbYDckepKHBTy19K6VyI’

url <- 'docs.google.com/spreadsheets/d/1W6nR5kg44fNaoRi_e_DkcBi-WbX5h9FumtFZX3JkiZM/I'
weather <- read.csv(text=gsheet2text(url, format='csv'), dec =',', stringsAsFactors=FALSE)
head(weather,50)
ABCDEFGHIJ0123456789
 
 
dt
<int>
date
<chr>
city_id
<int>
city_name
<chr>
lon
<dbl>
lat
<dbl>
temp
<dbl>
temp_min
<dbl>
1134909280001.10.2012 12:00702550Lviv24.0232449.8382615.0015.00
2134909280001.10.2012 12:00706483Kharkiv36.2500050.0000018.0013.75
3134909640001.10.2012 13:00703448Kiev30.5166750.4333317.2617.00
4134909640001.10.2012 13:00702550Lviv24.0232449.8382615.0015.00
5134909640001.10.2012 13:00698740Odessa30.7326246.4774722.8922.78
6134918280002.10.2012 13:00706483Kharkiv36.2500050.0000017.0013.75
7134918640002.10.2012 14:00698740Odessa30.7326246.4774722.8922.78
8134918640002.10.2012 14:00703448Kiev30.5166750.4333316.7316.11
9134919000002.10.2012 15:00702550Lviv24.0232449.8382616.0016.00
10134919000002.10.2012 15:00703448Kiev30.5166750.4333315.8815.00
summary(weather)
##        dt                date              city_id      
##  Min.   :1.349e+09   Length:193145      Min.   :698740  
##  1st Qu.:1.401e+09   Class :character   1st Qu.:698740  
##  Median :1.455e+09   Mode  :character   Median :703448  
##  Mean   :1.449e+09                      Mean   :702802  
##  3rd Qu.:1.499e+09                      3rd Qu.:706483  
##  Max.   :1.541e+09                      Max.   :706483  
##   city_name              lon             lat             temp       
##  Length:193145      Min.   :24.02   Min.   :46.48   Min.   :-26.00  
##  Class :character   1st Qu.:30.52   1st Qu.:46.48   1st Qu.:  2.00  
##  Mode  :character   Median :30.73   Median :50.00   Median : 10.54  
##                     Mean   :30.73   Mean   :49.16   Mean   : 10.42  
##                     3rd Qu.:36.25   3rd Qu.:50.43   3rd Qu.: 18.94  
##                     Max.   :36.25   Max.   :50.43   Max.   : 42.22  
##     temp_min          temp_max         pressure       humidity     
##  Min.   :-26.000   Min.   :-26.00   Min.   : 962   Min.   :  0.00  
##  1st Qu.:  2.000   1st Qu.:  2.22   1st Qu.:1010   1st Qu.: 59.00  
##  Median : 10.000   Median : 11.00   Median :1015   Median : 79.00  
##  Mean   :  9.996   Mean   : 10.79   Mean   :1015   Mean   : 73.15  
##  3rd Qu.: 18.000   3rd Qu.: 19.00   3rd Qu.:1021   3rd Qu.: 92.00  
##  Max.   : 42.220   Max.   : 47.22   Max.   :1054   Max.   :100.00  
##    wind_speed        wind_deg     clouds_all       weather_id   
##  Min.   : 0.000   Min.   :  0   Min.   :  0.00   Min.   :200.0  
##  1st Qu.: 2.000   1st Qu.: 80   1st Qu.:  0.00   1st Qu.:800.0  
##  Median : 3.000   Median :176   Median : 40.00   Median :800.0  
##  Mean   : 3.808   Mean   :177   Mean   : 41.36   Mean   :754.4  
##  3rd Qu.: 5.000   3rd Qu.:275   3rd Qu.: 80.00   3rd Qu.:803.0  
##  Max.   :58.000   Max.   :360   Max.   :100.00   Max.   :804.0  
##  weather_main       weather_description
##  Length:193145      Length:193145      
##  Class :character   Class :character   
##  Mode  :character   Mode  :character   
##                                        
##                                        
## 


Подготовим наши данные

weather$date <- as.Date(weather$date, '%d.%m.%Y %H:%M')
weather$year <- as.factor(year(as.POSIXlt(weather$date, format="%d/%m/%Y")))

oneMonthKiev <- weather %>%
  filter(date > '2018-03-01 00:00:00',date < '2018-03-31 00:00:00',city_name == 'Kiev')

oneMonthKievGroup <- weather %>%
  filter(date > '2018-03-01 00:00:00',date < '2018-03-31 00:00:00',city_name == 'Kiev') %>%
  group_by(date) %>% 
  summarise(temp = mean(temp))

weatherNum <- select(weather, c(7,10:14))


Базовые функции визуализации

  • plot(x) — график x
  • plot(x, y) — график зависимости y от x
  • hist(x) — гистограмма
  • barplot(x) — столбчатая диаграмма
  • dotchart(x) — диаграмма Кливленда
  • pie(x) — круговая диаграмма
  • boxplot(x) — график типа “коробочки с усами”
  • sunflowerplot(x, y) — то же, что и plot(), однако точки с одинаковыми координатами изображаются в виде “ромашек”, количество лепестков у которых пропорционально количеству таких точек
  • coplot(x˜y | z) — график зависимости y от x для каждого интервала значений z
  • interaction.plot(f1, f2, y) — если f1 и f2 — факторы, эта фукнция создаст график со средними значениями y в соответствии со значениями f1 (по оси х) и f2 (по оси у, разные кривые)
  • matplot(x, y) — график зависимости столбцов y от столбцов x
  • fourfoldplot(x) — изображает (в виде частей окружности) связь между двумя бинарными переменными в разных совокупностях
  • assocplot(x) — график Кохена-Френдли
  • mosaicplot(x) — мозаичный график остатков лог-линейной регрессии
  • pairs(x) — если х - матрица или таблица данных, эта функция изобразит диаграммы рассеяния для всех возможных пар переменных из х
  • plot.ts(x), ts.plot(x) — изображает временной ряд
  • qqnorm(x) — квантили
  • qqplot(x, y) — график зависимости квантилей y от квантилей х
  • contour(x, y, z) — выполняет интерполяцию данных и создает контурный график
  • filled.contour(x, y, z) — то же, что contour(), но заполняет области между контурами определёнными цветами
  • image(x, y, z) — изображает исходные данные в виде квадратов, цвет которых определяется значениями х и у
  • persp(x, y, z) — то же, что и image(), но в виде трехмерного графика
  • stars(x) — если x — матрица или таблица данных, изображает график в виде “звезд” так, что каждая строка представлена “звездой”, а столбцы задают длину сегментов этих “звезд”
  • symbols(x, y, …) — изображает различные символы в соответствии с координатами
  • termplot(mod.obj) — зображает частные эффекты переменных из регрессионной модели


plot

Визуализация одной переменной

plot(weather$temp)

Диаграммы рассеяния

plot(oneMonthKiev$date, oneMonthKiev$temp)

Параметры функции plot

xlab, ylab и main

Параметры xlab и ylab служат для изменения названий осей X и Y соответственно

plot(oneMonthKiev$date, oneMonthKiev$temp,
     xlab = 'Дата', ylab = 'Температура', main = 'Температура в Киеве')

type

Параметр type позволяет изменять внешний вид точек на графике. Он принимает одно из следующих текстовых значений:

“p” - точки (points; используется по умолчанию) “l” - линии (lines) “b” - изображаются и точки, и линии (both points and lines) “o” - точки изображаются поверх линий (points over lines) “h” - гистограмма (histogram) “s” - ступенчатая кривая (steps) “n” - данные не отображаются (no points)

plot(oneMonthKievGroup$date, oneMonthKievGroup$temp,
     xlab = 'Дата', ylab = 'Температура', main = 'Температура в Киеве',
     type = 'l')

xlim и ylim

Эти два параметра контролирут размах значений на каждой из осей графика. По умолчанию они оба принимают значение NULL - в этом случае размах выбирается программой автоматически.

plot(oneMonthKievGroup$date, oneMonthKievGroup$temp,
     xlab = 'Дата', ylab = 'Температура', main = 'Температура в Киеве',
     type = 'l', ylim = c(1,10))



hist

Гистограммы распределения строятся с помощью функции hist(). Чтобы изменить ширину кармана (столбца) гистограммы, необходимо задать параметр breaks =, а цвет задается в параметре col

hist(weather$temp,
     xlab = 'Температура', ylab = 'Частота', main = 'Распределение температуры в Украине')

hist(weather$temp,  breaks = 60,
     xlab = 'Температура', ylab = 'Частота', main = 'Распределение температуры в Украине')

hist(weather$temp,  breaks = 60, col = "lightblue", border = "pink",
     xlab = 'Температура', ylab = 'Частота', main = 'Распределение температуры в Украине')

hist(weather$temp,  breaks = 60, col = "lightblue", border = "pink",
     freq = FALSE,
     xlab = 'Температура', ylab = 'Частота', main = 'Распределение температуры в Украине')

hist(weather$temp,  breaks = 30, col = "lightblue", border = "pink",
     freq = FALSE,
     xlab = 'Температура', ylab = 'Частота', main = 'Распределение температуры в Украине')
lines(density(weather$temp), col = "red", lwd = 2)



boxplot

boxplot(temp ~ city_name, data = weather)

boxplot(temp ~ city_name, data = weather,
         xlab = "Города",
            ylab = "Температура",
            main = "Температура по городам Украины",
            col = "coral")

boxplot(temp ~ city_name, data = weather,
         xlab = "Температура",
            ylab = "Города",
            main = "Температура по городам Украины",
            col = c('chartreuse3', 'red' , 'cyan', 'darkorange1'),
            horizontal = TRUE)
grid()



Библиотека ggplot2

#install.packages('ggplot2', dep = T)

library(ggplot2)

Базовый шаблон ggplot

Посмотрим взаимосвязь температуры и давления

ggplot(data = weather) +
  geom_point(mapping = aes(x = temp, y = pressure))

Тоже самое, но на более разряженных данных за один месяц

ggplot(data = oneMonthKiev) +
  geom_point(mapping = aes(x = temp, y = pressure))

ggplot(data = weather) +
  geom_point(mapping = aes(x = temp, y = pressure, 
                           color = clouds_all))

ggplot(data = oneMonthKiev) +
  geom_point(mapping = aes(x = temp, y = pressure,
                           color = weather_main,
                           #shape = weather_main,
                           size = wind_speed)) +
  labs(
    title = "Погода в Киеве",
    subtitle = "Март 2018",
    caption = "По данным: https://openweathermap.org/",
    x = "Температура",
    y = "Атмосферное давление",
    color = "Погода",
    size = "Сила ветра"
  )

Панели

ggplot(data = weather) +
  geom_point(mapping = aes(x = temp, y = pressure,
                           color = weather_main,
                           size = wind_speed))+
  facet_wrap(~weather_main, nrow = 3)

ggplot(data = weather) +
  geom_point(mapping = aes(x = temp, y = pressure,
                           color = weather_main))+
  facet_grid(city_name~weather_main)

ggplot(data = weather) +
  geom_point(mapping = aes(x = temp, y = pressure,
                           color = weather_main))+
  facet_grid(.~city_name)

Геометрии

ggplot(data = weather,aes(x = temp, y = pressure)) +
  geom_smooth()

ggplot(data = weather) +
  geom_smooth(mapping = aes(x = temp, y = pressure,
                            linetype = city_name,
                            color = city_name))

ggplot(data = oneMonthKiev) +
  geom_point(mapping = aes(x = temp, y = pressure)) +
  geom_smooth(mapping = aes(x = temp, y = pressure))

ggplot(data = oneMonthKiev, mapping = aes(x = temp, y = pressure)) +
  geom_point() +
  geom_smooth()

ggplot(data = oneMonthKiev, mapping = aes(x = temp, y = pressure)) +
  geom_point(mapping = aes(color = weather_main)) +
  geom_smooth()

oneMonthKiev %>%
ggplot(aes(x = temp, y = pressure)) +
  geom_point(mapping = aes(color = weather_main)) +
  geom_smooth(data = filter(oneMonthKiev, weather_main == 'Rain'),
              se = F
  )

Статистики

ggplot(data = weather, mapping = aes(weather_main)) +
  geom_bar()

ggplot(data = weather, mapping = aes(weather_main)) +
  stat_count()

ggplot(data = weather) +
  geom_bar(mapping = aes(x = weather_main, y = ..prop.., group = 1))

ggplot(data = weather, mapping = aes(temp)) +
  geom_histogram(binwidth = 1) +
  theme_bw()

ggplot(data = weather, mapping = aes(weather$temp)) +
  stat_bin(binwidth = 1)

Позиционные настройки

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, color = weather_main))

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, fill = weather_main))

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, fill = city_name))

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, fill = city_name),
           position = 'fill'
           )

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, fill = city_name),
           position = 'dodge'
           )

ggplot(data = oneMonthKiev) +
  geom_point(mapping = aes(x = temp, y = pressure)
)

ggplot(data = oneMonthKiev) +
  geom_point(mapping = aes(x = temp, y = pressure),
            position = 'jitter'
)

Системы координат

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, fill = city_name)) +
  coord_flip()

ggplot(data = weather,mapping = aes(x = city_name,y = temp, fill = city_name)) +
  geom_boxplot() +
  coord_flip()

ggplot(data = weather) +
  geom_bar(mapping = aes(weather_main, fill = city_name)) +
  coord_polar()

corrplot

Очень удобная библиотека для изучения корреляции между переменными.

library(corrplot)

M <-cor(weatherNum)

corrplot(M, method = "circle", tl.cex=0.6, tl.srt = 45, tl.col = "black", type= "upper", order="hclust")

Интерактивные визуализации

plotly

#install.packages('plotly', dependencies = T)
library(plotly)

Scatter Plots

plot_ly(weather, y = ~temp,color = ~year, type = "box")
2012201320142015201620172018−20−10010203040
2012201320142015201620172018temp

Violin Plots

weather %>%
  plot_ly(
    x = ~year,
    y = ~temp,
    split = ~year,
    type = 'violin',
    box = list(
      visible = T
    ),
    meanline = list(
      visible = T
    )
  ) %>% 
  layout(
    xaxis = list(
      title = "Year"
    ),
    yaxis = list(
      title = "Temp",
      zeroline = F
    )
  )
2012201320142015201620172018−30−20−10010203040
2012201320142015201620172018YearTemp

3D Scatter Plots

plot_ly(oneMonthKiev, x = ~temp, y = ~pressure, z = ~humidity, color = ~weather_main) %>%
  add_markers() %>%
  layout(scene = list(xaxis = list(title = 'Temp'),
                     yaxis = list(title = 'Pressure'),
                     zaxis = list(title = 'Humidity')))
ClearCloudsDrizzleFogMistRainSnow

ggplotly

gp <- ggplot(data = weather,mapping = aes(x = temp, y = pressure,
                                linetype = city_name,
                                color = city_name)) +
        geom_smooth()

ggplotly(gp)
-2002040101010201030
KharkivKievLvivOdessatemppressurecity_name


Александр Васильев. DataStream. 18.01.2019

PS

Это и не только, на нашем, совместном с Data Science UA, курсе по визуализации данных
Data Science Visualization Course: 2.0.

Приглашаем Вас!